import { InterfaceStorageService, StorageScope } from "src/common/storage/storage";
import { injectable } from "src/common/services/di";
import { isUndefinedOrNull } from 'src/common/types';

interface InterfaceBrowserStorage {
  get(key: string): string | null;

  set(key: string, value: string): void;

  delete(key: string): void;
}

interface InterfaceStorageObj {
  expirytime: string;
  starttime: string;
  value: any;
}

export class Storage implements InterfaceBrowserStorage {
  private type: 'localStorage' | 'sessionStorage';

  constructor(type: 'local' | 'session' = 'local'){
    this.type = (type + 'Storage') as ('localStorage' | 'sessionStorage');
  };

  set(key: string, value: any, expirytime: number = 0): void{
    const storage = window[this.type];
    if(typeof window === 'undefined' || typeof storage === 'undefined')return;
    try{
      const temp: any = {};
      temp.starttime = new Date().getTime();
      temp.expirytime = expirytime || 0;
      temp.value = value;
      value = JSON.stringify(temp);

      storage.setItem(key, value);
    }catch(error){}
  };

  get(key: string): string | null{
    const storage = window[this.type];
    if(typeof window === 'undefined' || typeof storage === 'undefined')return null;
    const val = storage.getItem(key);

    if(!val){return null};

    try {
      const tempVal = JSON.parse(val) as InterfaceStorageObj;
      //就算是默认值expirytime都应该是0，如果变成undefined，说明存储过程出现了问题，那就不返回值，而是把整个对象返回回去
      if(typeof tempVal.expirytime === 'undefined'){return val};
      //正常情况下就直接返回存储的值
      if(+tempVal.expirytime === 0){ return tempVal.value };
      if(new Date().getTime() - (+tempVal.starttime) > (+tempVal.expirytime)){
        //存储值超过期望时间，就过期了就把缓存删除掉
        this.delete(key);
        return null;
      }else {
        return tempVal.value;
      }
    }catch(error){
      if(val){
        return val
      }else{
        return null;
      }
    }
  };

  delete(key: string): void {
    if(typeof window === 'undefined' || typeof window[this.type] === 'undefined'){ return };
    window[this.type].removeItem(key);
  };

  //保留方法，暂时不确定能拿来干啥
  asMap(){
    const mapResult = new Map<string, string>();
    const storage = window[this.type];
    const keys = Object.keys(storage);
    keys.forEach((key: string) => {
      mapResult.set(key, storage.getItem(key) as string);
    });
    return mapResult;
  };
};

@injectable()
export class LocalStorageService implements InterfaceStorageService {
  readonly _servicebrand: undefined;

  private readonly globalCache = new Storage();
  private readonly workspaceCache = new Storage('session');

  private getCache(scope: StorageScope){
    return scope === StorageScope.GLOBAL ? this.globalCache : this.workspaceCache;
  };

  get(key: string, scope: StorageScope, fallbackValue: string): string;
	get(key: string, scope: StorageScope, fallbackValue?: string): string | undefined{
    const value = this.getCache(scope).get(key);

    if(isUndefinedOrNull(value)){
      return fallbackValue;
    }

    return value;
  };

  getBoolean(key: string, scope: StorageScope, fallbackValue: boolean): boolean;
	getBoolean(key: string, scope: StorageScope, fallbackValue?: boolean): boolean | undefined {
		const value = this.getCache(scope).get(key);

		if (isUndefinedOrNull(value)) {
			return fallbackValue;
		}

		return value === 'true';
	};

  getNumber(key: string, scope: StorageScope, fallbackValue: number): number;
	getNumber(key: string, scope: StorageScope, fallbackValue?: number): number | undefined {
		const value = this.getCache(scope).get(key);

		if (isUndefinedOrNull(value)) {
			return fallbackValue;
		}

		return parseInt(value, 10);
	};

  store(key: string, value: string | boolean | number | undefined | null, scope: StorageScope): Promise<void> {
    if(isUndefinedOrNull(value)){
      return this.remove(key, scope);
    };

    const valueStr = String(value);

    const currentValue = this.getCache(scope).get(key);
    if(currentValue === valueStr){
      return Promise.resolve();
    };

    this.getCache(scope).set(key, valueStr);

    return Promise.resolve();
  };

  remove(key: string, scope: StorageScope): Promise<void> {
    this.getCache(scope).delete(key);

    return Promise.resolve();
  };

  logStorage(): void {
    console.info('todo...');
  };
}
